package server

import (
	"context"
	"go-rpc-2/server_register_and_found/register"
	"google.golang.org/grpc"
	"log"
	"net"
	"time"
)

type Server struct {
	*grpc.Server
	register    register.Register
	duration    time.Duration
	name        string
	weight      int
	group       string
	interceptor []grpc.UnaryServerInterceptor
}

func (s *Server) Start(network, addr string) error {
	listener, err := net.Listen(network, addr)
	if err != nil {
		return err
	}

	if s.register != nil {
		ctx, cancel := context.WithTimeout(context.Background(), s.duration)
		err = s.register.RegisterService(ctx, register.ServiceInstance{
			ServiceName: s.name,
			Addr:        listener.Addr().String(),
			Weight:      s.weight,
			Group:       s.group,
		})
		cancel()
	}

	err = s.Serve(listener)
	if err != nil {
		return err
	}
	return nil
}

func (s *Server) Close() {
	if s.register != nil {
		err := s.register.Close()
		if err != nil {
			log.Printf("server: close register err:%v", err)
		}
	}
	s.Server.GracefulStop()
}

type Opt func(s *Server)

func WithRegister(r register.Register, duration time.Duration) Opt {
	return func(s *Server) {
		s.register = r
		s.duration = duration
	}
}

func WithWeight(w int) Opt {
	return func(s *Server) {
		s.weight = w
	}
}
func WithGroup(group string) Opt {
	return func(s *Server) {
		s.group = group
	}
}

func WithInterceptors(interceptors ...grpc.UnaryServerInterceptor) Opt {
	return func(s *Server) {
		s.interceptor = interceptors
	}
}

func NewServer(name string, opts ...Opt) *Server {
	s := &Server{name: name}
	for _, opt := range opts {
		opt(s)
	}
	grpcOpts := make([]grpc.ServerOption, 0, 2)
	if s.interceptor != nil {
		grpcOpts = append(grpcOpts, grpc.ChainUnaryInterceptor(s.interceptor...))
	}
	s.Server = grpc.NewServer(grpcOpts...)

	return s
}
